package netmon.gui;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.util.Timer;

import netmon.snmp.OIDConverter;
import netmon.snmp.SNMPEngine;

/**
 * Controller for the Graphical User Interface
 * @author Marc Backes
 */
public class NetmonGUIController {
	private static String version = "v0.4";									// Version number
	NetmonMainJFrame mainJFrm;												// Reference to the Graphical User Interface
	private SNMPEngine snmpE;												// Reference to the facade 'SNMPEngine'
	private OIDConverter oidC = new OIDConverter();							// SNMP OID Converter
	private UpdateGUITT updateGuiTT = new UpdateGUITT(this);				// Reference to 'UpdateGUITT'
	private Timer refreshTimer = new Timer();								// Reference to the timer (who starts 'updateGuiTT')
	private boolean firstRun = true;										// Variable is it is the first run or not

	/**
	 * Contructor: Creates <i>NetmonMainJFrame</i>, <i>SNMPEngine</i> object and initializes GUI
	 */
	public NetmonGUIController() {
		mainJFrm = new NetmonMainJFrame(version, this);						// Creating instance of the GUI
		snmpE = new SNMPEngine();											// Creating instance of the SNMP facade
		refreshTimer.schedule(updateGuiTT, 1000, 1000);						// Start the timer with 'updateGuiTT'
		fillHosts();														// Fill the GUI with hosts (read from 'hosts.conf')											
	}

	/**
	 * Show GUI without initializing the values
	 */
	public void coldStart(){
		mainJFrm.setVisible(true);		
	}

	/**
	 * Show GUI with initializing the values
	 */
	public void warmStart(){
		refreshOnDemand();
		coldStart();
	}

	/**
	 * Hide GUI
	 */
	public void hide(){
		mainJFrm.setVisible(false);
	}

	/**
	 * Version of the GUIController
	 * @return Program version of <i>NetmonGUIController</i>
	 */
	public String getVersion(){
		return version;
	}

	/**
	 * Refresh all values in the GUI
	 */
	public void refreshOnDemand(){

		getInterfaceNumber();
		String OS = snmpE.getStringByName("sysDescr");
		/* "Parsing" operating system */
		if(OS.contains("Linux")){
			OS = "Linux (Kernel: "+OS.substring(OS.indexOf("2."),OS.indexOf('#')-1)+")";
		}
		// TODO: Other operating systems have to be tested!

		/* Setting retreived values to the GUI */
		mainJFrm.setHostAndIP(snmpE.getStringByName("sysName"), hostToIp(snmpE.getStringByName("sysName")));
		mainJFrm.setOS(OS);
		mainJFrm.setResponsible(snmpE.getStringByName("sysContact"));
		mainJFrm.setLocation(snmpE.getStringByName("sysLocation"));
		mainJFrm.setUptime(snmpE.getStringByName("hrSystemUptime"));
		mainJFrm.setDroppedPackages("<Not implemented yet>");
		mainJFrm.setMacAddress("AA-BB-CC-DD-EE");
		mainJFrm.setNOfConnections(snmpE.getStringByName("tcpActiveOpens"));
		mainJFrm.setUpSpeed("Waiting...");
		mainJFrm.setDownSpeed("Waiting...");
		mainJFrm.setnOfRunningProcesses(snmpE.getStringByName("hrSystemProcesses"));
		fillInterfaces();
	}

	/**
	 * Refreshes the values in the GUI which are refreshed every second by <i>updateGuiTT</i>
	 */
	public void continouslyRefresh(){
		mainJFrm.setUptime(snmpE.getStringByName("hrSystemUptime"));					// Uptime
		mainJFrm.setNOfConnections(snmpE.getStringByName("tcpActiveOpens"));			// Current connections
		mainJFrm.setnOfRunningProcesses(snmpE.getStringByName("hrSystemProcesses"));	// Running processes
	}

	/**
	 * Refreshes the values in the GUI for upload- and download speed
	 * @param downspeed Downloading transfer rate
	 * @param upspeed Uploading transfer rate
	 */
	public void refreshTransferRates(String downspeed, String upspeed){
		mainJFrm.setDownSpeed(downspeed);		// Download
		mainJFrm.setUpSpeed(upspeed);			// Upload
	}
	
	/**
	 * Fills the <i>cbmHosts</i> from <i>NetmonMainJFrame</i> with hosts read from <i>hosts.conf</i>
	 */
	private void fillHosts(){
		/* Fill the combobox with data from the file */
		mainJFrm.cleanHosts();
		try {
			FileInputStream FIStream = new FileInputStream("src/hosts.conf");			// Open file
			DataInputStream DIStream = new DataInputStream(FIStream);
			BufferedReader br = new BufferedReader(new InputStreamReader(DIStream));	// Create buffer
			String strLine;
			/* Read every line of the file and add it in 'mainJFrame' */
			while ((strLine = br.readLine()) != null) {
				mainJFrm.addHost(strLine);
			}
			DIStream.close();
		} catch (Exception e) {
			System.err.println("Error while reading 'hosts.conf': " + e.getMessage());
		}
	}

	/**
	 * Fills the <i>cbmInterfaces</i> from <i>NetmonMainJFrame</i> with the interfaces read from the SNMP
	 */
	private void fillInterfaces(){
		mainJFrm.cleanInterfaces();
		int nOfIf = snmpE.getIntById(".1.3.6.1.2.1.2.1.0");								// Number of interfaces

		for (int i = 1; i <= nOfIf; i++) {
			mainJFrm.addInterface(snmpE.getStringById(".1.3.6.1.2.1.2.2.1.2."+i));		// Interface description + index
		}
	}

	/**
	 * Get the current selected interface from the GUI
	 * @return Interface number
	 */
	public int getInterfaceNumber(){
		return mainJFrm.getInterfaceNumber();
	}

	/**
	 * Event called when the host changed in the GUI
	 * @param host Hostname
	 */
	public void changeHost(String host){
		/*
		 * If it is the first run, we do not want to display it.
		 * Only the first change of host.
		 */
		if(!firstRun){
			snmpE.setHost(hostToIp(host));
			refreshOnDemand();
			updateGuiTT.setReady(true);
		} else {
			firstRun = false;
		}
	}
	
	/**
	 * Event called when the interface changed in the GUI
	 */
	public void changedInterface(){
		if(!firstRun){		// Should always be the case, but safe is safe!
			mainJFrm.setMacAddress(snmpE.getStringById(oidC.get("ifPhysAddress")+"."+mainJFrm.getInterfaceNumber()));
			updateGuiTT.setReady(true);
			firstRun = false;
		}
	}

	/**
	 * Refreshes static things and set the <i>updateGuiTT</i> to -> ready
	 */
	public void refresh(){
		refreshOnDemand();
		updateGuiTT.setReady(true);
	}

	/**
	 * Resolves the IP address of a given host
	 * @param host Host to resolve
	 * @return IP address of the host
	 */
	private String hostToIp(String host){
		InetSocketAddress isa;
		isa = new InetSocketAddress(host, 123);
		return isa.getAddress().toString().substring(isa.getAddress().toString().indexOf('/')+1);
	}

	/**
	 * Reset the loading bars in the GUI (maximum = 0)
	 */
	public void resetBars(){
		mainJFrm.resetBars();
	}
}
